﻿using Jaina;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Runtime;
using System.Text;
using System.Threading;
using System.Threading.RateLimiting;
using YS.Domain.IoT.Extension;
using YS.Domain.IoT.Model;
using YS.Domain.IoT.Receive;
using YS.Domain.IoT.Util;
using YS.K12.Application.IoT.Service;
using System.Security.Cryptography;
using TouchSocket.Sockets;
using System.Collections.Concurrent;
using Microsoft.Extensions.Logging;
using NLog;
using YS.K12.Application.IoT.RedisHub;
namespace YS.K12.Core.IoT.Plugin
{
    /// <summary>
    ///消息处理插件
    /// </summary>
    public class TcpReceivedPlugin : PluginBase, ITcpReceivedPlugin, ITcpReceivingPlugin
    {
        private readonly IEventPublisher _capPublisher;
        private readonly ITcpService _tcpService;
        private readonly IHttp _http;
        public readonly ILogger<TcpReceivedPlugin> _logger;
        private readonly RedisHubLifetimeManager _redisHub;


        public TcpReceivedPlugin(
            IEventPublisher capPublisher,
            ITcpService tcpService,
            IHttp http,
             ILogger<TcpReceivedPlugin> logger,
              RedisHubLifetimeManager redisHub)
        {
            _capPublisher = capPublisher;
            _tcpService = tcpService;
            _http = http;
            _logger = logger;
            _redisHub=redisHub;
        }
        /// <summary>
        /// 在收到适配器数据时触发，根据适配器类型，数据可能在ByteBlock或者IRequestInfo里面。
        /// </summary>
        /// <param name="client"></param>
        /// <param name="e"></param>
        /// <returns></returns>
        public async Task OnTcpReceived(ITcpSession client, ReceivedDataEventArgs e)
        {
            //数据适配器
            if (e.RequestInfo is BetweenAndRequestInfo bRequest)
            {
                bRequest.ClientId = client.GetClientId();
                var request = bRequest.DataAdapter();
                var privkey = new VendToken();
                if (!client.TryGetAuth(out bool isLoggedIn))
                {
                    isLoggedIn = false;
                }
                //机器申请密钥
                if (request.Key == "1000")
                {
                    //特殊处理
                    privkey.PrivaKey = request.Body.FromJsonString<VendToken>()?.PubKey ?? string.Empty;
                }
                //机器登录
                else if (request.Key == "1111")
                {
                    // 更新登录状态
                    client.SetAuth(true);
                    await _redisHub.SubscribeToConnection(client);
                    //重置Id
                    await _tcpService.ResetIdAsync(client.GetClientId(), request.Mid);
                }
                // 检查登录状态
                else if (!isLoggedIn)
                {
                    _logger.LogInformation($" 客户端 {bRequest.ClientId} 尚未登录，拒绝处理非1000/1111请求");
                    await client.CloseAsync();

                    return;
                }
                else {
                    //其他指令也要获取密钥
                    //获取服务器密钥
                    privkey = await _http.GetPrivKey(request.Mid);
                }
                //计算签名
                var sign = SignUtil.GetSign(request.Body, request.Mid, request.MainInfo.TimeSp.ToString(), privkey.PrivaKey, Encoding.GetEncoding("GB2312"));
                if (sign != request.Sign)
                {
                    _logger.LogError($" 解码失败设备{request.Mid}的{request.Key}协议,系统:{sign},安卓Body:{request.Sign}");
                    await client.CloseAsync();

                    return;
                }
                await _capPublisher.PublishAsync(GetEventId(request), request);

            }
            await e.InvokeNext();
        }
        /// <summary>
        /// 在收到原始数据时触发，所有的数据均在ByteBlock里面。
        /// </summary>
        /// <param name="client"></param>
        /// <param name="e"></param>
        /// <returns></returns>
        /// <exception cref="NotImplementedException"></exception>
        public Task OnTcpReceiving(ITcpSession client, ByteBlockEventArgs e)
        {
            return e.InvokeNext();
        }


        #region 工具方法
        /// <summary>
        ///获取发布事件ID
        /// </summary>
        /// <param name="myRequest"></param>
        /// <returns></returns>
        private string GetEventId(RequestInfo myRequest)
        {

            return $"{myRequest.Key}{(string.IsNullOrEmpty(myRequest.Version) ? string.Empty : string.Format(":{0}", myRequest.Version))}";
        }


        #endregion


    }
}
